👪 Excel Bestand

Het auto-categorizatie stuk van ons huidige Excel sheet is mogelijk handig voor gezinnen die net beginnen met een eigen sheet. Deze pagina is dan ook een goodie. Het is niet direct gerelateerd aan de "manier" omdat "de manier" in elk tool gedaan kan worden.

Tabbladen

Het basis Excel sheet is simpel bestaat uit een aantal sheets:

  1. In het eerste sheet copy en paste je simpelweg de bank-exports van al je transacties onder elkaar. In ons spreadsheet hebben we er rond de 17.000 in staan vanaf 2005. Hiernaast staan een extra kolommen zoals:
    • Een kolom waarin je een term/category/post/label kunt plaatsen bij die specifieke transactie
    • Die kolom wordt automatisch gevuld door het categorizatie script maar... als je hem zelf al ingevuld hebt dan zal je eigen keuze niet overschreven worden.
    • Als de auto categorizatie een andere waarde vindt dan die jezelf ingevuld hebt dan zal deze in een kolom ernaast geplaatst worden, handig als dubbelcheck
    • Een kolom die ons verteld wie de transactie gedaan heeft aan de hand van het pasnummer (als het een betaling was met een pasnummer)
    • Kolommen met subcategorieen als het label puntjes bevat, puntjes worden opgevat als hierarchie
  2. Sheet waar je regels in kunt noteren bijvoorbeeld: rekeningnummer X is label "donald duck" sheet1 uitstapje naar de toekomst:
    Dit is de huidige opzet, die prima werkt. Maar het kan nog beter :) Het zou handiger zijn als iedereen met een spreadsheet zijn regels kan delen. Dan hoeft maar 1 keer iemand de Donald Duck te categorizeren en bij alle andere mensen wordt deze dan ook automatisch gecategorizeeerd. Dit vereist wel het hebben van gelijke taxomomie of het hebben van meerdere taxonomieen, waarvan een de A-B-C=D taxonomie is.
    In de echte wereld zijn er systemen waar functies gestandaardiseerd zijn. In XACML bijvoorbeeld is er een standaard lijst met functies zoals "string-equal". Deze verwacht dan een attribuut, die altijd bestaat uit een "categorie" met een eigenschap, als ook een waarde. Als we dit spreadsheet gaan uitbreiden dan zal het die kanten op gaan. Want dat betekent dat we een stapje omhoog gaan en 1 categorie hebben: transactie, die dan meerdere eigenschappen heeft. Die eigenschappen verbind je dan aan waardes en de specifieke instantie van een functie sla je dan op in json of xml zodat we alle functies die mensen dan willen delen kunnen gaan verzamelen op een plek. Dat is handig want dan hoef je ze zelf niet meer toe te voegen. In theorie zouden alle budget software systemen dan van dezelfde pool gebruik kunnen maken. En we leveragen dan op open OASIS standaarden voor de uitwisseling van deze benoemde functies. Dat vereist een aparte pagina met de regels, dat staat nog op TODO :)
    Een tweede verbetering hierin is dan om die json of xml van die benoemde functie "donald duck" uit te breiden met nog meer gestandaardiseerde informatie zoals metadata (adres, link, opzeggen, forum, prijsverloop over jaren) maar ook met vrije smarte regels die de input zijn voor een gezin om keuzes te maken. Ook hier is XACML een idee generator: niet alleen data kan gestandaardiseerd worden uitgewisseld maar ook regels.
    We breiden dus in de tweede verbetering die donaldduck.json van "benoemde functie" naar "iets met veel meer data dan alleen herkenningsregel" via open standaarden.
    Dat vereist wel dat je minimaal de A-B-C-D taxonomie gebruikt
    En ook dat kan een derde verbetering hebben: als mensen eenmaal die auto regels gebruiken en delen. Dan kan je het zo gek maken als je zelf wilt. Je kunt dan functies toevoegen die niet alleen categorizeren maar "alles" kunnen: als je een rekening hebt van een specifiek vakantiehuisje dan zou iemand een regel kunnen maken die daar weer op acteert e.d. en als je een pinbon hebt van de MacDonalds in Groningen dan zou je ook ervaringen kunnen delen via die functie voor die specifieke MacDonals OF een functie kunnen toevoegen die iets doet met alle macdonalds. Dat kan zo gek worden als mensen zelf verzinnen
    Dit is allemaal vrij simpel dus we verwachten dit ergens op korte termijn te releasen.
  3. Een sheet waarin alle labels staan, zodat je ze handig uit een pulldown menu kunt selecteren. Op diezelfde sheet staat achter die kolom het "totaal" en dan per jaar het totaal. Zo fungeert die slide als lijst van je labels en tegelijkertijd als een snel overzicht.
  4. (optioneel) Via

Categorizatie script

Het categorizatie script leest alle regels in sheet 2 en brengt de labels aan in sheet 1. Je kunt deze copy en pasten in een Excel Module. En in het menu van Excel kun je een icoontje maken dat linkt aan de module. Zo kun je door het klikken op het icoontje het script runnen.
"In de beginne" zal het script niet alles categorizeren omdat je nog niet genoeg regels hebt gemaakt. Dus met en met kun je regels toevoegen door telkens degene die overblijven in het regelsheet te plaatsen. Het is niet heel veel werk maar ook niet weinig werk.

idee: Als we in GitHub regels zouden delen dan zou dit voor iedereen minder werk zijn.

                #If False Then
                Dim Range, Accounts, BudgetLine, Category, Color, RowContent
            #End If
            Option Explicit

            Function Col_Letter(lngCol As Long) As String
                Dim vArr
                vArr = Split(Cells(1, lngCol).Address(True, False), "$")
                Col_Letter = vArr(0)
            End Function


            Sub OptimizeCode_Begin()

                Application.ScreenUpdating = False
                EventState = Application.EnableEvents
                Application.EnableEvents = False
                CalcState = Application.Calculation
                Application.Calculation = xlCalculationManual
                PageBreakState = ActiveSheet.DisplayPageBreaks
                ActiveSheet.DisplayPageBreaks = False
            End Sub

            Sub OptimizeCode_End()
                ActiveSheet.DisplayPageBreaks = PageBreakState
                Application.Calculation = CalcState
                Application.EnableEvents = EventState
                Application.ScreenUpdating = True
            End Sub


            '
            ' Main sub to start
            '
            Sub Categorize()
                Dim importsheetRow As Long
                Dim RuleRow As Long
                Dim RuleColumn As Long
                Dim RuleColumnLetter As String
                Dim RuleImportLookupColumn As String
                Dim RuleComparisonRule As String
                Dim IsEmptyCell As Boolean
                Dim RuleComparisonValue As Range
                Dim ImportValue As Range
                Dim RuleIsTrue As Boolean
                Dim ImportCategoryColumn As String
                Dim CurrentCategory As String
                Dim FutureCategory As String
                Dim FutureCategoryColor As Long
                Dim ShouldWriteCategory As Boolean
                Dim AmountRuleMatches As Integer

                 Call OptimizeCode_Begin

                For importsheetRow = 2 To ThisWorkbook.Sheets("Import").Range("A" & Rows.Count).End(xlUp).row
                    ImportCategoryColumn = ThisWorkbook.Sheets("Rules").Range("A1").Text
                    CurrentCategory = ThisWorkbook.Sheets("Import").Range(ImportCategoryColumn + CStr(importsheetRow)).Text
                    If True Or (CurrentCategory = "") Then
                        For RuleRow = 4 To ThisWorkbook.Sheets("Rules").Range("A" & Rows.Count).End(xlUp).row
                            RuleIsTrue = True
                            AmountRuleMatches = 0
                            For RuleColumn = 3 To ThisWorkbook.Sheets("Rules").Cells(1, Columns.Count).End(xlToLeft).Column
                                RuleColumnLetter = Col_Letter(RuleColumn)
                                RuleImportLookupColumn = ThisWorkbook.Sheets("Rules").Range(RuleColumnLetter + "1").Text
                                RuleComparisonRule = ThisWorkbook.Sheets("Rules").Range(RuleColumnLetter + "3").Text

                                If Not IsEmpty(ThisWorkbook.Sheets("Rules").Range(RuleColumnLetter + CStr(RuleRow))) Then
                                    Set RuleComparisonValue = ThisWorkbook.Sheets("Rules").Range(RuleColumnLetter + CStr(RuleRow))
                                    Set ImportValue = ThisWorkbook.Sheets("Import").Range(RuleImportLookupColumn + CStr(importsheetRow))
                                    If (RuleComparisonRule = "Smaller") Then
                                        If Not (RuleComparisonValue.Value < ImportValue.Value) Then
                                            RuleIsTrue = False
                                            Exit For
                                        Else
                                            AmountRuleMatches = AmountRuleMatches + 1
                                        End If
                                    End If
                                    If (RuleComparisonRule = "Larger") Then
                                        If Not (RuleComparisonValue.Value > ImportValue.Value) Then
                                            RuleIsTrue = False
                                            Exit For
                                        Else
                                            AmountRuleMatches = AmountRuleMatches + 1
                                        End If
                                    End If
                                    If (RuleComparisonRule = "Equal") Then
                                        If (IsNumeric(RuleImportLookupColumn)) Then
                                            If Not (RuleComparisonValue.Value = ImportValue.Value) Then
                                                RuleIsTrue = False
                                                Exit For
                                            Else
                                                AmountRuleMatches = AmountRuleMatches + 1
                                            End If
                                        Else
                                            If Not (RuleComparisonValue.Text = ImportValue.Text) Then
                                                RuleIsTrue = False
                                                Exit For
                                            Else
                                                AmountRuleMatches = AmountRuleMatches + 1
                                            End If
                                        End If
                                    End If
                                    If (RuleComparisonRule = "Contains") Then
                                        If (ImportValue.Text = "") Or (Not (ImportValue.Text Like "*" + RuleComparisonValue.Text + "*")) Then
                                            RuleIsTrue = False
                                            Exit For
                                        Else
                                            AmountRuleMatches = AmountRuleMatches + 1
                                        End If
                                    End If
                                    If (RuleComparisonRule = "StartsWith") Then
                                        If (ImportValue.Text = "") Or (Not Left(ImportValue.Text, Len(RuleComparisonValue)) = RuleComparisonValue) Then
                                            RuleIsTrue = False
                                            Exit For
                                        Else
                                            AmountRuleMatches = AmountRuleMatches + 1
                                        End If
                                    End If
                                    If (RuleComparisonRule = "Empty") Then
                                        If ImportValue.Text <> "" Then
                                            RuleIsTrue = False
                                            Exit For
                                        Else
                                            AmountRuleMatches = AmountRuleMatches + 1
                                        End If
                                    End If
                                End If
                            Next RuleColumn
                            If RuleIsTrue = True And AmountRuleMatches > 0 Then
                                FutureCategory = ThisWorkbook.Sheets("Rules").Range("A" + CStr(RuleRow)).Text
                                If CurrentCategory = "" Then
                                    ThisWorkbook.Sheets("Import").Range(ImportCategoryColumn + CStr(importsheetRow)).Value = FutureCategory
                                    ThisWorkbook.Sheets("Import").Range(ImportCategoryColumn + CStr(importsheetRow)).Interior.ColorIndex = 4
                                ElseIf CurrentCategory <> FutureCategory Then
                                    ThisWorkbook.Sheets("Import").Range(ImportCategoryColumn + CStr(importsheetRow)).Interior.ColorIndex = 3
                                    ThisWorkbook.Sheets("Import").Range("AB" + CStr(importsheetRow)).Value = FutureCategory
                                ElseIf CurrentCategory = FutureCategory Then
                                    ThisWorkbook.Sheets("Import").Range(ImportCategoryColumn + CStr(importsheetRow)).Interior.ColorIndex = 50
                                Else
                                    ThisWorkbook.Sheets("Import").Range(ImportCategoryColumn + CStr(importsheetRow)).Interior.ColorIndex = 9
                                End If
                                Exit For
                            End If
                        Next RuleRow
                    End If
                Next importsheetRow

                Call OptimizeCode_End

                MsgBox "Klaar!"
            End Sub